const React = require('react');
const fs = require('fs-extra');
const path = require('path');
const _ = require('lodash');
const chalk = require('chalk');
const inliner = require('inliner');
const MarkdownView = require('../lib/MarkdownView.js');
const renderToStaticMarkup = require('react-dom/server').renderToStaticMarkup;
const CWD = process.cwd();
let config;

function getPageHtml(rawContent, pageIndex) {
    pageIndex = pageIndex - 3;
    const offset = _.get(config.offset, pageIndex + 1, '');
    let offsetTop = 0, offsetHeight = 0;
    if (offset) {
        const list = offset.split(/,|，/);
        offsetTop = +list[0] || 0;
        offsetHeight = (+list[1] || 0) + offsetTop;
    }
    const height = config.pageSize.h + offsetHeight;
    const top =  - (config.pageSize.h * pageIndex - offsetTop);
    const style = top < 0 ? ` style="top:${top}px"` : '';
    return `
    <div class="book-content-container" style="height:${height}px">
        <div class="book-content"${style}>
            ${renderToStaticMarkup(<MarkdownView source={rawContent} pageIndex={pageIndex} page={{ config }} />)}
        </div>
    </div>
    <span class="page-number">${+pageIndex + 1}</span>
    `;
}
function writeToFile(url, distFile) {
    return new Promise(resolve => {
        new inliner(url, { images: true, inlinemin: true }, function (error, html) {
            if (error) {
                console.log(chalk.red(event));
            } else {
                // console.log('start write to:', distFile);
                if (_.isFunction(distFile)) {
                    distFile(html)
                } else {
                    fs.writeFileSync(distFile, html);
                    console.log('write to:', distFile);
                }
            }
            resolve();
        })
        .on('progress', function (event) {
            // console.log(chalk.green(event));
        });
    });
}
async function startMDBook(configPath, port, verbose, open, build) {
    if (/\.md$/.test(configPath)) {
        config = { srcPath: configPath }
    } else {
        config = require(path.resolve(CWD, configPath));
    }
    !config.pageSize && (config.pageSize = { w: 400, h: 520 });
    config.rootDir = path.dirname(config.srcPath);

    const pageHtmlList = {};
    const distPath = path.join(CWD, config.distPath);
    const express = require('express');
    const bodyParser = require('body-parser');
    const morgan = require('morgan');
    const app = express();
    verbose && app.use(morgan('short'));
    app.use(bodyParser.json());
    if (config.staticDir) {
        app.use('/', express.static(config.staticDir));
        if (build) {
            app.use('/pages', express.static(config.staticDir));
        }
    }
    app.use(express.static(config.rootDir));
    app.use(express.static(path.join(__dirname, 'res')));
    config.rootDir === '.' && (config.rootDir = '');
    const rawContent = fs.readFileSync(config.srcPath, 'utf8');

    app.get('/', (req, res) => {
        let { pageIndex, o, c, build } = req.query;
        if (pageIndex == undefined) {
            c = config.pageCountOffset;
        }
        const html = renderToStaticMarkup(<MarkdownView source={rawContent} page={{ config }} />)
        res.send(fs.readFileSync(path.join(__dirname, 'res/book/index.md.test.html'), 'utf-8').replace('<%pageIndex%>', pageIndex).replace('<%o%>', o).replace('<%pageCountOffset%>', c).replace('<%build%>', build).replace('<%children%>', html).replace('<%children1%>', html));
    });
    app.get('/main.html', async (req, res) => {
        const { pageCount, build } = req.query;
        const list = renderToStaticMarkup(<MarkdownView source={rawContent} page={{ config }} />)
        let html = fs.readFileSync(path.join(__dirname, 'res/book/index.md.template.html'), 'utf-8').replace(/<%pageCount%>/g, pageCount).replace(/<%preEndPage%>/g, pageCount - 1).replace('<%build%>', build).replace('<%cover%>', config.cover);
        if (build) {
            html = html.replace('<%children%>', list);
        }
        res.send(html);
    });
    app.get('/pages/*.html', (req, res) => {
        const pageIndex = _.last(req.url.split('/')).replace('.html', '');
        const html = getPageHtml(rawContent, pageIndex);
        res.send(html);
    });
    app.get('/pages.js', (req, res) => {
        res.send(`var pageHtmlList = ${JSON.stringify(pageHtmlList)}`);
    });
    app.post('/build', async (req, res) => {
        const { pageCount, realPageCount } = req.body;
        console.log('/build [recv]:', req.body);
        for (let i=0; i<=realPageCount; i++) {
            await writeToFile(`http://localhost:${port}/pages/${i+3}.html`, html => pageHtmlList[i+3] = html);
        }
        fs.ensureDirSync(distPath);
        await writeToFile(`http://localhost:${port}/main.html?pageCount=${pageCount}&build=1`, path.join(distPath, 'index.html'));
        res.send('已经打包成功，文件在'+distPath);
        setTimeout(()=>{
            process.exit(0);
        }, 500);
    });

    const server = app.listen(port);
    server.on('listening', function () {
        const url = 'http://localhost:' + port;
        console.log('Open', url);
        const gulp = require('gulp');
        const browserSync = require('browser-sync').create();
        if (build) {
            return browserSync.init({
                proxy: `${url}?build=1`,
                notify: false,
                open: true,
            });
        }
        gulp.task('browser', function () {
            browserSync.init({
                proxy: url,
                files: [{
                    match: [path.join(CWD, config.srcPath) + '/**/*.md'],
                    fn: async function (event, file) {
                        browserSync.reload();
                    }
                }],
                notify: false,
                open,
            });
        });
        gulp.start(['browser']);
    });
    server.on('error', function (err) {
        console.log('open error on port:', port);
        startMDBook(configPath, port + 1, verbose, open, build);
    });
}

module.exports = startMDBook;
